﻿using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.IO;
using System.Globalization;
using System.Text.RegularExpressions;
using System.Collections;
using System.IO.Compression;
using System.Collections.Generic;
using AjaxControlToolkit;
using System.Text;



namespace AjaxControlToolkitEx
{
    public class PageEx : Page
    {
        protected virtual string TempFolder
        {
            get
            {
                throw new NotImplementedException();
            }
        }

        private string PageStateUID;
        private string PageStateFileName
        {
            get
            {
                if (this.DesignMode)
                    return Server.MapPath(String.Format("{0}/{1}_{2}_{3}.tmp", TempFolder, "DesignTimeSession", Request.ServerVariables["Path_Info"].Replace("/", "_"), PageStateUID));

                return Server.MapPath(String.Format("{0}/{1}_{2}_{3}.tmp", TempFolder, Session.SessionID, Request.ServerVariables["Path_Info"].Replace("/", "_"), PageStateUID));
            }
        }

        protected override object LoadPageStateFromPersistenceMedium()
        {
            PageStatePersister pageStatePersister = this.PageStatePersister;
            try
            {
                pageStatePersister.Load();
                PageStateUID = pageStatePersister.ViewState as string;
            }
            catch
            {
                PageStateUID = Guid.NewGuid().ToString();
            }

            string m_viewState;
            LosFormatter m_formatter;
            object viewStateBag;

            try
            {

                string file = PageStateFileName;
                //StreamReader sr = new StreamReader(file);
                //m_viewState = sr.ReadToEnd();
                //sr.Close();
                m_viewState = Session[file].ToString();

                m_formatter = new LosFormatter();

                viewStateBag = m_formatter.Deserialize(m_viewState);
            }
            catch
            {
                Response.Redirect("~");
                return null;
                //throw new HttpException("The View State is invalid or corrupted");
            }

            return viewStateBag;
        }
        protected override void SavePageStateToPersistenceMedium(object viewStateBag)
        {
            if (string.IsNullOrEmpty(PageStateUID))
                PageStateUID = Guid.NewGuid().ToString();

            LosFormatter m_formatter = new LosFormatter();
            string file = PageStateFileName;
            //StreamWriter sw = new StreamWriter(file);
            //m_formatter.Serialize(sw, viewStateBag);
            //sw.Close();

            StringBuilder sb = new StringBuilder();
            TextWriter sw = new StringWriter(sb);
            m_formatter.Serialize(sw, viewStateBag);
            Session[file] = sb.ToString();

            PageStatePersister pageStatePersister = this.PageStatePersister;
            pageStatePersister.ViewState = PageStateUID;
            pageStatePersister.Save();

            return;
        }

        //protected override object LoadPageStateFromPersistenceMedium()
        //{
        //    PageStatePersister pageStatePersister = this.PageStatePersister;
        //    try
        //    {
        //        pageStatePersister.Load();
        //        PageStateUID = pageStatePersister.ViewState as string;
        //    }
        //    catch
        //    {
        //        PageStateUID = Guid.NewGuid().ToString();
        //    }

        //    string m_viewState;
        //    LosFormatter m_formatter;
        //    object viewStateBag;

        //    string file = PageStateFileName;
        //    StreamReader sr = new StreamReader(file);
        //    m_viewState = sr.ReadToEnd();
        //    sr.Close();

        //    m_formatter = new LosFormatter();

        //    try
        //    {
        //        viewStateBag = m_formatter.Deserialize(m_viewState);
        //    }
        //    catch
        //    {
        //        throw new HttpException("The View State is invalid or corrupted");
        //    }

        //    return viewStateBag;
        //}
        //protected override void SavePageStateToPersistenceMedium(object viewStateBag)
        //{
        //    if (string.IsNullOrEmpty(PageStateUID))
        //        PageStateUID = Guid.NewGuid().ToString();

        //    string file = PageStateFileName;
        //    StreamWriter sw = new StreamWriter(file);
        //    LosFormatter m_formatter = new LosFormatter();
        //    m_formatter.Serialize(sw, viewStateBag);
        //    sw.Close();

        //    PageStatePersister pageStatePersister = this.PageStatePersister;
        //    pageStatePersister.ViewState = PageStateUID;
        //    pageStatePersister.Save();

        //    return;
        //}
        private PageStatePersister persistor;
        protected override PageStatePersister PageStatePersister
        {
            get
            {
                if (this.persistor == null)
                    this.persistor = new CompressedPageStatePersister(Page);

                return this.persistor;
            }
        }
        internal static class Compressor
        {
            public static byte[] Compress(byte[] data)
            {
                MemoryStream output = new MemoryStream();
                GZipStream gzip = new GZipStream(output,
                                  CompressionMode.Compress, true);
                gzip.Write(data, 0, data.Length);
                gzip.Close();
                return output.ToArray();
            }

            public static byte[] Decompress(byte[] data)
            {
                MemoryStream input = new MemoryStream();
                input.Write(data, 0, data.Length);
                input.Position = 0;
                GZipStream gzip = new GZipStream(input,
                                  CompressionMode.Decompress, true);
                MemoryStream output = new MemoryStream();
                byte[] buff = new byte[64];
                int read = -1;
                read = gzip.Read(buff, 0, buff.Length);
                while (read > 0)
                {
                    output.Write(buff, 0, read);
                    read = gzip.Read(buff, 0, buff.Length);
                }
                gzip.Close();
                return output.ToArray();
            }
        }
        internal class CompressedPageStatePersister : PageStatePersister
        {
            public CompressedPageStatePersister(Page page)
                : base(page)
            {
            }

            public override void Load()
            {
                string viewState = Page.Request.Form["__VSTATE"];
                byte[] bytes = Convert.FromBase64String(viewState);
                bytes = Compressor.Decompress(bytes);
                LosFormatter formatter = new LosFormatter();
                object obj = formatter.Deserialize(Convert.ToBase64String(bytes));
                Pair pair = (Pair)obj;
                ViewState = pair.First;
                ControlState = pair.Second;
            }

            public override void Save()
            {
                Pair pair = new Pair(ViewState, ControlState);
                LosFormatter formatter = new LosFormatter();
                StringWriter writer = new StringWriter();
                formatter.Serialize(writer, pair);
                string viewStateString = writer.ToString();
                byte[] bytes = Convert.FromBase64String(viewStateString);
                bytes = Compressor.Compress(bytes);
                ScriptManager.RegisterHiddenField(Page, "__VSTATE", Convert.ToBase64String(bytes));
            }
        }

        #region id map
        internal static Dictionary<string, string> GetIDMap(Page page)
        {
            if (page.Session["cIDMap" + page.UniqueID] == null)
                page.Session["cIDMap" + page.UniqueID] = new Dictionary<string, string>();
            return page.Session["cIDMap" + page.UniqueID] as Dictionary<string, string>;
        }
        internal static void SetIDMap(Page page, Dictionary<string, string> idmap)
        {
            page.Session["cIDMap" + page.UniqueID] = idmap;
        }
        internal static Dictionary<string, string> GetIDMap2(Page page)
        {
            if (page.Session["cIDMap2" + page.UniqueID] == null)
                page.Session["cIDMap2" + page.UniqueID] = new Dictionary<string, string>();
            return page.Session["cIDMap2" + page.UniqueID] as Dictionary<string, string>;
        }
        internal static void SetIDMap2(Page page, Dictionary<string, string> idmap)
        {
            page.Session["cIDMap2" + page.UniqueID] = idmap;
        }

        public static string GetUniqueID(Page page, string baseUniqueID)
        {
            //return baseUniqueID;

            Dictionary<string, string> idmap = GetIDMap(page);
            Dictionary<string, string> idmap2 = GetIDMap2(page);
            if (!idmap.ContainsKey(baseUniqueID))
            {
                int i = idmap.Keys.Count;
                bool found = false;
                string newid = baseUniqueID;
                do
                {
                    newid = string.Format("c{0}", i++);

                    found = idmap.ContainsValue(newid);

                } while (found);
                idmap.Add(baseUniqueID, newid);
                idmap2.Add(newid, baseUniqueID);
                SetIDMap(page, idmap);
                SetIDMap2(page, idmap2);
            }
            return idmap[baseUniqueID];
        }

        #endregion

        public override Control FindControl(string id)
        {
            if (this.DesignMode)
                return base.FindControl(id);

            Dictionary<string, string> idmap2 = GetIDMap2(this);

            if (idmap2.ContainsKey(id))
                return base.FindControl(idmap2[id]);

            return base.FindControl(id);
        }
        protected override Control FindControl(string id, int pathOffset)
        {
            if (this.DesignMode)
                return base.FindControl(id, pathOffset);

            Dictionary<string, string> idmap2 = GetIDMap2(this);

            if (idmap2.ContainsKey(id))
                return base.FindControl(idmap2[id], pathOffset);

            return base.FindControl(id, pathOffset);
        }

    }

    public class Helper
    {
        private static Regex reg = new Regex(@"(?<=[^])\t{2,}|(?<=[>])\s{2,}(?=[<])|(?<=[>])\s{2,11}(?=[<])|(?=[\n])\s{2,}");
        public static string Trim(string content)
        {
            return content; // reg.Replace(content, string.Empty);
        }
        public static void RunScript(Control control, Type type, string key, string script, bool addScriptTags)
        {
            ScriptManager.RegisterStartupScript(control, type, key, Trim(script), addScriptTags);
        }
        public static void SetupScript(Control control, Type type, string key, string script, bool addScriptTags)
        {
            ScriptManager.RegisterClientScriptBlock(control, type, key, Trim(script), addScriptTags);
        }
    }

    public class UpdatePanelEx : UpdatePanel
    {
        //private bool _rendered;
        //protected override void RenderChildren(HtmlTextWriter writer)
        //{

        //    if (this.IsInPartialRendering)
        //    {
        //        if (this._rendered)
        //        {
        //            return;
        //        }
        //        HtmlTextWriter writer2 = new HtmlTextWriter(new StringWriter(CultureInfo.CurrentCulture));
        //        base.RenderChildren(writer2);
        //        string content = writer2.InnerWriter.ToString();
        //        {
        //            int pos = content.IndexOf('|');
        //            if (pos >= 0)
        //            {
        //                int length = Convert.ToInt32(content.Substring(0, pos));
        //                content = content.Substring(pos + 1);
        //                pos = content.IndexOf('|');
        //                if (pos >= 0)
        //                {
        //                    string type = content.Substring(0, pos);
        //                    content = content.Substring(pos + 1);
        //                    pos = content.IndexOf('|');
        //                    if (pos >= 0)
        //                    {
        //                        string id = content.Substring(0, pos);
        //                        content = content.Substring(pos + 1);
        //                        pos = content.LastIndexOf('|');
        //                        if (pos >= 0)
        //                        {
        //                            content = content.Substring(0, pos);
        //                        }
        //                    }
        //                }
        //            }
        //        }
        //        EncodeStringEx(writer, "updatePanel", this.ClientID, content);
        //    }
        //    else
        //    {
        //        HtmlTextWriter writer2 = new HtmlTextWriter(new StringWriter(CultureInfo.CurrentCulture));
        //        base.RenderChildren(writer2);
        //        string content = writer2.InnerWriter.ToString();
        //        writer.Write(Helper.Trim(content));
        //    }
        //    this._rendered = true;
        //}

        public bool IsUpdating
        {
            get
            {
                return base.RequiresUpdate;
            }
        }

        internal static void EncodeStringEx(TextWriter writer, string type, string id, string content)
        {
            if (id == null)
            {
                id = string.Empty;
            }
            if (content == null)
            {
                content = string.Empty;
            }
            content = Helper.Trim(content);

            int num = 0;
            for (int i = 0; i < content.Length; i++)
            {
                if (content[i] == '\x00ff')
                {
                    num++;
                }
                else if (content[i] == '\0')
                {
                    num += 2;
                }
            }
            writer.Write((content.Length + num).ToString(CultureInfo.InvariantCulture));
            writer.Write('|');
            writer.Write(type);
            writer.Write('|');
            writer.Write(id);
            writer.Write('|');
            int index = 0;
            char[] buffer = content.ToCharArray();
            for (int j = 0; j < buffer.Length; j++)
            {
                if (buffer[j] == '\x00ff')
                {
                    writer.Write(buffer, index, j - index);
                    writer.Write("\x00ff\x00ff");
                    index = j + 1;
                }
                else if (buffer[j] == '\0')
                {
                    writer.Write(buffer, index, j - index);
                    writer.Write("\\\x00ff\\");
                    index = j + 1;
                }
            }
            writer.Write(buffer, index, buffer.Length - index);
            writer.Write('|');
        }

        private string m_cachedUniqueID = null;
        public override string UniqueID
        {
            get
            {
                if (this.DesignMode)
                    return base.UniqueID;

                if (m_cachedUniqueID == null)
                    m_cachedUniqueID = GetUniqueID(Page, base.UniqueID);
                return m_cachedUniqueID;
            }
        }

        private static Dictionary<string, string> GetIDMap(Page page)
        {
            if (page.Session["uIDMap" + page.UniqueID] == null)
                page.Session["uIDMap" + page.UniqueID] = new Dictionary<string, string>();
            return page.Session["uIDMap" + page.UniqueID] as Dictionary<string, string>;
        }
        private static void SetIDMap(Page page, Dictionary<string, string> idmap)
        {
            page.Session["uIDMap" + page.UniqueID] = idmap;
        }

        internal static string GetUniqueID(Page page, string baseUniqueID)
        {
            //return baseUniqueID; 
            Dictionary<string, string> idmap = GetIDMap(page);
            if (!idmap.ContainsKey(baseUniqueID))
            {
                int i = idmap.Keys.Count;
                bool found = false;
                string newid = baseUniqueID;
                do
                {
                    newid = string.Format("u{0}", i++);

                    found = idmap.ContainsValue(newid);

                } while (found);
                idmap.Add(baseUniqueID, newid);
                SetIDMap(page, idmap);
            }
            return idmap[baseUniqueID];
        }

    }

    public class ExtenderControlBaseEx : ExtenderControlBase
    {
        protected string GetClientID(string controlId)
        {
            Control c = FindControlHelper(controlId);

            if (c != null)
            {
                controlId = c.ClientID;
            }

            return controlId;
        }
        //protected string GetClientID(string id)
        //{
        //    return string.Format("{0}_{1}", ClientID, id);
        //}
        public override Control FindControl(string id)
        {
            Dictionary<string, string> idmap2 = PageEx.GetIDMap2(Page);

            if (idmap2.ContainsKey(id))
                return base.FindControl(idmap2[id]);

            return base.FindControl(id);
        }
        protected override Control FindControl(string id, int pathOffset)
        {
            Dictionary<string, string> idmap2 = PageEx.GetIDMap2(Page);

            if (idmap2.ContainsKey(id))
                return base.FindControl(idmap2[id], pathOffset);

            return base.FindControl(id, pathOffset);
        }

        internal class HiddenFieldEx : HiddenField
        {
            private string m_cachedUniqueID = null;
            public override string UniqueID
            {
                get
                {
                    if (this.DesignMode)
                        return base.UniqueID;

                    if (m_cachedUniqueID == null)
                        m_cachedUniqueID = PageEx.GetUniqueID(Page, base.UniqueID);
                    return m_cachedUniqueID;
                }
            }
        }
    }

    public class AppHelper
    {
        public static void BeginCompression()
        {
            string acceptEncoding = HttpContext.Current.Request.Headers["Accept-Encoding"];
            if (string.IsNullOrEmpty(acceptEncoding))
                return;
            acceptEncoding = acceptEncoding.ToLower();

            string urlAbsolutePath = HttpContext.Current.Request.Url.AbsolutePath;
            if (!string.IsNullOrEmpty(urlAbsolutePath))
            {
                urlAbsolutePath = urlAbsolutePath.ToLower();

                if (urlAbsolutePath.EndsWith(".ashx") || urlAbsolutePath.EndsWith(".axd"))
                    return;
            }
            if (HttpContext.Current.Request.QueryString["_TSM_HiddenField_"] != null)
                return;

            Stream filterstream = HttpContext.Current.Response.Filter;
            if ((acceptEncoding.Contains("gzip") || acceptEncoding.Contains("x-gzip") || acceptEncoding.Contains("*")))
            {
                if (HttpContext.Current.CurrentHandler is System.Web.UI.Page
                    && HttpContext.Current.Request["HTTP_X_MICROSOFTAJAX"] != null
                    && HttpContext.Current.Request["X-MICROSOFTAJAX"] != null
                    )
                {
                    GZipStream2 newstream = new GZipStream2();
                    HttpContext.Current.Response.Filter = newstream;
                    HttpContext.Current.Items["CompressionStream"] = newstream;
                }
                else
                {
                    HttpContext.Current.Response.Filter = new GZipStream(filterstream, CompressionMode.Compress);
                }
                HttpContext.Current.Response.AppendHeader("Content-Encoding", "gzip");
            }
            else if (acceptEncoding.Contains("deflate"))
            {
                HttpContext.Current.Response.Filter = new DeflateStream(filterstream, CompressionMode.Compress);
                HttpContext.Current.Response.AppendHeader("Content-Encoding", "deflate");
            }
        }
        public static void EndCompression()
        {
            GZipStream2 stream = (GZipStream2)HttpContext.Current.Items["CompressionStream"];
            if (stream != null)
                stream.CloseAndWriteAll(HttpContext.Current.Response.OutputStream);
        }
    }
    #region Stream
    internal class GZipStream2 : Stream
    {
        private MemoryStream _ms;
        private GZipStream _gzip;

        public GZipStream2()
        {
            _ms = new MemoryStream(1024);
            _gzip = new GZipStream(_ms, CompressionMode.Compress);
        }

        public override bool CanRead
        {
            get { return _gzip.CanRead; }
        }

        public override bool CanSeek
        {
            get { return _gzip.CanSeek; }
        }

        public override bool CanWrite
        {
            get { return _gzip.CanWrite; }
        }

        public override void Flush()
        {
        }

        public override long Length
        {
            get { return _gzip.Length; }
        }

        public override long Position
        {
            get
            {
                return _gzip.Position;
            }
            set
            {
                _gzip.Position = value;
            }
        }

        public override int Read(byte[] buffer, int offset, int count)
        {
            return _gzip.Read(buffer, offset, count);
        }

        public override long Seek(long offset, SeekOrigin origin)
        {
            return _gzip.Seek(offset, origin);
        }

        public override void SetLength(long value)
        {
            _gzip.SetLength(value);
        }

        public override void Write(byte[] buffer, int offset, int count)
        {
            _gzip.Write(buffer, offset, count);
        }

        public void CloseAndWriteAll(Stream outStream)
        {
            _gzip.Close();
            _ms.Close();
            byte[] buffer = _ms.ToArray();
            outStream.Write(_ms.ToArray(), 0, buffer.Length);
        }
    }
    #endregion

}